package ua.kpi.flats.dao.impl;

import java.util.List;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Property;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import ua.kpi.flats.dao.ApplicationDao;
import ua.kpi.flats.entity.BuyApplication;
import ua.kpi.flats.entity.District;
import ua.kpi.flats.entity.Flat;
import ua.kpi.flats.entity.SaleApplication;
import ua.kpi.flats.entity.SuitableOption;

@Repository("applicationDao")
public class ApplicationDaoImpl extends HibernateDaoSupport implements ApplicationDao {

	@Autowired
	public ApplicationDaoImpl(HibernateTemplate hibernateTemplate) {
		super.setHibernateTemplate(hibernateTemplate);
	}
	
	@Transactional(readOnly = true,			       
			       isolation = Isolation.READ_COMMITTED)
	public List<District> getDistricts() {
		return getHibernateTemplate().loadAll(District.class);
	}
	
	@Transactional
	public void addBuy(BuyApplication app) {
		getHibernateTemplate().refresh(app.getDistrict());
		getHibernateTemplate().refresh(app.getClient());
		
		getHibernateTemplate().save(app);
	}

	@Transactional
	public void addFlat(Flat flat) {
		getHibernateTemplate().save(flat);
	}
	
	@Transactional
	public void addSale(SaleApplication app) {
		getHibernateTemplate().refresh(app.getClient());
		getHibernateTemplate().save(app);
	}
	
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true,			      
			       isolation = Isolation.READ_COMMITTED)
    public List<BuyApplication> getBuyApplications(int from,int limit) {
		
		DetachedCriteria criteria = DetachedCriteria.forClass(BuyApplication.class);
		criteria.addOrder(Order.desc("createDate"));		
		
		return getHibernateTemplate().findByCriteria(criteria, from, limit);	
	}
	
	@Transactional(readOnly = true,			       
   	               isolation = Isolation.READ_COMMITTED)
	public long buyAppCount() {
		return DataAccessUtils.longResult(getHibernateTemplate().find("SELECT COUNT(*) FROM BuyApplication"));
	}
	
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true,			       
			       isolation = Isolation.READ_COMMITTED)
    public List<SaleApplication> getSaleApplications(int from, int limit) {
		DetachedCriteria criteria = DetachedCriteria.forClass(SaleApplication.class);
		criteria.addOrder(Order.desc("createDate"));
		
		return getHibernateTemplate().findByCriteria(criteria, from, limit);
	}
	
	@Transactional(readOnly = true,			       
			       isolation = Isolation.READ_COMMITTED)
    public long saleAppCount() {
		return DataAccessUtils.longResult(getHibernateTemplate().find("SELECT COUNT(*) FROM SaleApplication"));
	}
	
	@Transactional(readOnly = true,			       
			       isolation = Isolation.READ_COMMITTED)
	public BuyApplication getBuyApp(long id) {
		return getHibernateTemplate().get(BuyApplication.class, id);
	}
	
	@Transactional(readOnly = true,			       
			       isolation = Isolation.READ_COMMITTED)
    public SaleApplication getSaleApp(long id) {
		return getHibernateTemplate().get(SaleApplication.class, id);
	}
	
	@Transactional(isolation = Isolation.READ_COMMITTED)
    public void removeBuyApp(BuyApplication app) {
		getHibernateTemplate().delete(app);
	}
	
	@Transactional(isolation = Isolation.READ_COMMITTED) 
    public void removeSaleApp(SaleApplication app) {
		getHibernateTemplate().delete(app);
	}
	
	@SuppressWarnings("unchecked")
	@Transactional(isolation = Isolation.READ_COMMITTED,
			       readOnly = true)
    public List<BuyApplication> waitingApps(DetachedCriteria criteria, int from,int limit) {				
		return getHibernateTemplate().findByCriteria(criteria, from ,limit);		
	}
	
	@Transactional(isolation = Isolation.READ_COMMITTED,
			       readOnly = true)
    public long getWaitingAppsCount(DetachedCriteria criteria) {		
		criteria.setProjection(Property.forName("id").count());
		return DataAccessUtils.longResult(getHibernateTemplate().findByCriteria(criteria));
	}
	
	@SuppressWarnings("unchecked")
	@Transactional(isolation = Isolation.READ_COMMITTED,
			       readOnly = true)
    public List<SuitableOption> getOptions(long appId) {
		return getHibernateTemplate().find("SELECT so FROM SuitableOption so " +
				"WHERE so.application.id = ?", appId);
	}
	
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true,
			       isolation = Isolation.READ_COMMITTED)
	public List<BuyApplication> getActiveBuyApp(DetachedCriteria criteria, int from,int limit) {
		return getHibernateTemplate().findByCriteria(criteria, from, limit);
	}
	
	@Transactional(readOnly = true,
			       isolation = Isolation.READ_COMMITTED)
    public long activeAppCount(DetachedCriteria criteria) {
		criteria.setProjection(Property.forName("id").count());
		return DataAccessUtils.longResult(getHibernateTemplate().findByCriteria(criteria));
	}
	
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true,
			       isolation = Isolation.READ_COMMITTED)
    public SaleApplication getSaleAppByOption(long optionId) {
		return (SaleApplication) DataAccessUtils.singleResult(getHibernateTemplate().find("" +
				"SELECT sa FROM SuitableOption so,SaleApplication sa,Flat f WHERE" +
				" f.id = so.flat.id AND sa.flat.id = f.id AND so.id = ?", optionId));
	}
}


